using System;
using System.Collections.Generic;
using System.IO;
using ExcelDataReader;
using UnityEditor;
using UnityEngine;

namespace Cavy.ExcelToText.Editor
{
    public class ExcelToTxt : EditorWindow
    {
        [MenuItem("Cavy/ExcelToText/ExcelToTxt")]
        static void Excel2ScriptableObject() {
            ExcelToTxt window = GetWindow<ExcelToTxt>("Excel To Txt");
            window.minSize = new Vector2(540f, 320f);
            window.maxSize = new Vector2(4000f, 4000f);
        }
        
        bool mGUIStyleInited = false;
        GUIStyle mStyleTextArea;
        private Vector2 mScroll;
        private string _ignoreChar = "//";

        private void OnGUI()
        {
            Color oColor = GUI.backgroundColor;
            if (!mGUIStyleInited) {
                mGUIStyleInited = true;
                mStyleTextArea = GUI.skin.FindStyle("TextArea") ?? GUI.skin.FindStyle("AS TextArea");
            }
            EditorGUILayout.Space(10);
            EditorGUILayout.LabelField("使用说明");
            EditorGUILayout.BeginVertical();
            EditorGUILayout.LabelField("导出数据结果：(1行1列) {列分隔符} (1行2列) {列分隔符} (1行3列) {行分隔符} \n                            (2行1列) {列分隔符} (2行2列) {列分隔符}...", GUILayout.Height(30));
            EditorGUILayout.LabelField("忽略行和列：在Excel中第一行和第一列的单元格的值中，在前面添加 双斜杠(//) 会忽略该行或者改列的导出  (注意：第一列不会被忽略)");
            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.LabelField("分隔符配置：行分隔符和列分隔符填字符串时会使用字符串分隔，如果配置数字则会转化为char类型, 比如换行(10)、单元格分隔符(31, US)");
            if (EditorGUILayout.LinkButton("查看更多十进制ASCII"))
            {
                ASCII.ShowASCII();
            }
            EditorGUILayout.EndHorizontal();
            EditorGUILayout.EndVertical();
            EditorGUILayout.Space(10);
            GUILayout.BeginHorizontal();;
            float buttonSize = 0.8f;
            GUILayout.Space(position.width * Mathf.Max(0, 1 - buttonSize) / 2);
            if (GUILayout.Button("添加配置", GUILayout.MaxWidth(position.width * buttonSize), GUILayout.Height(30)))
            {
                Config.I.AddNew();
            }
            GUILayout.EndHorizontal();
            EditorGUILayout.Space(10);
            mScroll = EditorGUILayout.BeginScrollView(mScroll, false, false);
            for (int i = 0; i < Config.I.data.Length; i++)
            {
                var config = Config.I.data[i];
                GUI.backgroundColor = (i & 1) == 0 ? new Color(0.6f, 0.6f, 0.7f) : new Color(0.8f, 0.8f, 0.8f);
                Color cacheColor = GUI.backgroundColor;
                EditorGUILayout.BeginVertical(mStyleTextArea);
                EditorGUILayout.Space(10);
                EditorGUILayout.BeginHorizontal();
                EditorGUILayout.LabelField($"Excel 文件", string.IsNullOrEmpty(config.path) ? "(Not Selected)" : config.path);
                GUI.backgroundColor = oColor;
                
                if (!string.IsNullOrEmpty(config.path))
                {
                    if (GUILayout.Button("打开", GUILayout.Width(88f)))
                    {
                        EditorUtility.OpenWithDefaultApp(config.path);
                    }
                }
                if (GUILayout.Button("选择Excel", GUILayout.Width(88f))) {
                    string p = EditorUtility.OpenFilePanel("Select Excel File", ".", "xlsx");
                    if (!string.IsNullOrEmpty(p)) {
                        string projPath = Application.dataPath;
                        projPath = projPath.Substring(0, projPath.Length - 6);
                        if (p.StartsWith(projPath)) { p = p.Substring(projPath.Length, p.Length - projPath.Length); }
                        config.path = p;
                        Config.I.Save();
                        GUI.changed = true;
                    }
                }
                EditorGUILayout.EndHorizontal();
                EditorGUILayout.BeginHorizontal();
                string exportPath = EditorGUILayout.TextField("Txt导出路径", string.IsNullOrEmpty(config.exportPath) ? "(Not Selected)" : config.exportPath);
                if (!string.IsNullOrEmpty(config.exportPath) && exportPath != config.exportPath)
                {
                    config.exportPath = exportPath;
                    SaveConfig();
                }
                if (GUILayout.Button("选择导出路径", GUILayout.Width(88f))) {
                    if (!string.IsNullOrEmpty(config.path))
                    {
                        int fIndex = config.path.LastIndexOf('/') + 1;
                        int lIndex = config.path.LastIndexOf('.');
                        string fileName = config.path.Substring(fIndex, lIndex - fIndex);
                        string p = EditorUtility.OpenFolderPanel("选择导出路径", Application.dataPath, "");
                        if (!string.IsNullOrEmpty(p))
                        {
                            int lastIndex = Application.dataPath.LastIndexOf("Assets");
                            if (lastIndex >= 0)
                            {
                                string projectPath = Application.dataPath.Substring(0, lastIndex);
                                string relativePath = p.Replace(projectPath, "").Replace('\\', '/');
                                config.exportPath = relativePath + $"/{fileName}.bytes";
                                Config.I.Save();
                                GUI.changed = true;
                            }
                        }
                    }
                }
                EditorGUILayout.EndHorizontal();
                EditorGUILayout.BeginHorizontal();
                string col = EditorGUILayout.TextField("列分隔符", config.colSplit, GUILayout.MaxWidth(this.position.width - 100));
                if (col != config.colSplit)
                {
                    config.colSplit = col;
                    SaveConfig();
                }
                GUI.backgroundColor = Color.red;
                if (GUILayout.Button("删除配置", GUILayout.Width(88f))) {
                    Config.I.Remove(i);
                }
                GUI.backgroundColor = oColor;
                EditorGUILayout.EndHorizontal();
                EditorGUILayout.BeginHorizontal();
                string row = EditorGUILayout.TextField("行分隔符", config.rowSplit,GUILayout.MaxWidth(position.width - 100));
                if (row != config.rowSplit)
                {
                    config.rowSplit = row;
                    SaveConfig();
                }
                GUI.backgroundColor = Color.green;
                if (GUILayout.Button("导出数据", GUILayout.Width(88f)))
                {
                    ExportData(config);
                }
                GUI.backgroundColor = oColor;
                EditorGUILayout.EndHorizontal();
                EditorGUILayout.Space(10);
                EditorGUILayout.EndVertical();
            }
            EditorGUILayout.EndScrollView();
            Event e = Event.current;

            // 判断点击事件是否发生在文本框外
            if (e.type == EventType.MouseDown)
            {
                GUI.FocusControl(null); // 移除焦点
            }
        }

        private void SaveConfig()
        {
            Config.I.Save();
        }

        private void ExportData(ExcelToTxtConfig config)
        {
            if (string.IsNullOrEmpty(config.exportPath) || config.exportPath == "(Not Selected)")
            {
                ShowNotification(new GUIContent($"未配置Excel路径"));
                return;
            };
            
            if (!File.Exists(config.path))
            {
                ShowNotification(new GUIContent($"{config.path}未找到Excel文件"));
                return;
            };
            
            // 行分隔符和列分隔符 转化
            char? col = null;
            char? row = null;
            col = int.TryParse(config.colSplit, out int colIntValue) ? (char) colIntValue : char.TryParse(config.colSplit, out char colCharValue) ? colCharValue : null;
            row = int.TryParse(config.rowSplit, out int rowIntValue) ? (char) rowIntValue : char.TryParse(config.rowSplit, out char rowCharValue) ? rowCharValue : null;
            string colSplit = ""; colSplit += col == null ? config.colSplit : col;
            string rowSplit = ""; rowSplit += row == null ? config.rowSplit : row;
           
            // 读取Excel
            string copyFilePath = config.path.Replace(".xlsx", "_temp.xlsx");
            File.Copy(config.path, copyFilePath);
            Stream fileStream = File.OpenRead(copyFilePath);
            IExcelDataReader reader = ExcelReaderFactory.CreateOpenXmlReader(fileStream);
            
            System.Data.DataSet data = reader.AsDataSet();
            fileStream.Close();
            reader.Dispose();
            File.Delete(copyFilePath);
            
            // 写入数据
            List<int> ignoreCol = new List<int>();
            string content = "";
            for (int tableIndex = 0; tableIndex < data.Tables.Count; tableIndex++)
            {
                ignoreCol.Clear();
                var table = data.Tables[tableIndex];
                if (table.TableName.Length >= 2 && table.TableName.Substring(0, 2) == _ignoreChar)
                {
                    continue;
                }

                if (table.Rows.Count > 0)
                {
                    var firstRow = table.Rows[0].ItemArray;
                    for (int i = 1; i < firstRow.Length; i++)
                    {
                        if (firstRow[i].ToString().Length >= 2 && firstRow[i].ToString().Substring(0, 2) == _ignoreChar)
                        {
                            ignoreCol.Add(i);
                        }
                    }
                }
                for (int rowIndex = 0; rowIndex < table.Rows.Count; rowIndex++)
                {
                    var rows = table.Rows[rowIndex].ItemArray;
                    if (rows.Length > 0 && rows[0].ToString().Length >=2 && rows[0].ToString().Substring(0, 2) == _ignoreChar)
                    {
                        continue;
                    }
                    for (int colIndex = 0; colIndex < rows.Length; colIndex++)
                    {
                        if (ignoreCol.Contains(colIndex)) continue;
                        string itemValue = rows[colIndex].ToString();
                        if (itemValue.Contains(colSplit) || itemValue.Contains(rowSplit))
                        {
                            ShowNotification(new GUIContent("Excel中的数据存在和行分隔符或列分隔符重复的字符，请修改后重试"));
                            return;
                        }
                        if (colIndex == rows.Length - 1)
                            content += rows[colIndex].ToString();
                        else
                            content += $"{rows[colIndex].ToString()}{colSplit}";
                    }

                    if (rowIndex < table.Rows.Count - 1)
                    {
                        content += rowSplit;
                    }
                }
            }
            File.WriteAllText(config.exportPath, content);
            AssetDatabase.SaveAssets();
            AssetDatabase.Refresh();
            ShowNotification(new GUIContent($"导出数据成功"));
        }

        [Serializable]
        public class Config
        {
            public ExcelToTxtConfig[] data = new ExcelToTxtConfig[0];
            
            private static string SETTINGS_PATH = "ProjectSettings/ExcelToTxt.txt";
            private static Config _i;
            public static Config I
            {
                get
                {
                    if (_i == null)
                    {
                        if (File.Exists(SETTINGS_PATH))
                        {
                            var text = File.ReadAllText(SETTINGS_PATH);
                            _i = JsonUtility.FromJson<Config>(text);
                        }
                    }
                    if(_i == null){
                    {
                        _i = new Config();
                    }}

                    return _i;
                }
            }

            public void Save()
            {
                File.WriteAllText(SETTINGS_PATH, JsonUtility.ToJson(this));
            }

            public void AddNew()
            {
                ExcelToTxtConfig[] newData = new ExcelToTxtConfig[data.Length + 1];
                data.CopyTo(newData, 0);
                data = newData;
                Save();
            }

            public void Remove(int index)
            {
                ExcelToTxtConfig[] newData = new ExcelToTxtConfig[data.Length - 1];
                for (int i = 0, sub = 0; i < data.Length; i++)
                {
                    if (i == index)
                    {
                        sub++;
                        continue;
                    }

                    int tI = i - sub;
                    newData[tI] = data[i];
                }

                data = newData;
                Save();
            }
        }

        [Serializable]
        public class ExcelToTxtConfig
        {
            public string path;
            public string exportPath;
            public string colSplit = "|";
            public string rowSplit = "10";
        }
    }
}
